package lesson5;

import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.lang.instrument.ClassDefinition;
import java.lang.instrument.Instrumentation;

// 有通过配置Maven来达到加载Agent的实例 https://www.cnblogs.com/liboware/p/15090408.html
// https://lanshiqin.com/b67783e4/
public class LoadAgent {

    public static void premain(String agentArgs, Instrumentation instrumentation) {
        try {
            File f = new File("/media/mazhi/sourcecode/workspace/projectjava/LiveClass/target/classes/User.class");
            ClassFileWatcher watcher = new ClassFileWatcher(instrumentation, f);
            watcher.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static class ClassFileWatcher extends Thread {

        private File classFile;
        private long lastModified;
        private Instrumentation instrumentation;
        private boolean firstRun = true;

        ClassFileWatcher(Instrumentation instrumentation, File classFile) {
            this.classFile = classFile;
            this.instrumentation = instrumentation;
            lastModified = classFile.lastModified();
        }

        @Override
        public void run() {
            while (true) {
                if (firstRun || (lastModified != classFile.lastModified())) {
                    firstRun = false;
                    lastModified = classFile.lastModified();
                    reDefineClass(instrumentation, classFile);
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    private static void reDefineClass(Instrumentation instrumentation, File classFile) {
        byte[] reporterClassFile = new byte[(int) classFile.length()];
        DataInputStream in;
        try {
            in = new DataInputStream(new FileInputStream(classFile));
            in.readFully(reporterClassFile);
            in.close();
            ClassDefinition reporterDef = new ClassDefinition(Class.forName("lesson3.User"), reporterClassFile);
            instrumentation.redefineClasses(reporterDef);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


